package com.acme.bankapp.service.bank.network;

import com.acme.bankapp.domain.bank.Bank;
import com.acme.bankapp.service.bank.network.command.Command;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * This class represents server which reply on {@link BankClient} object request
 *
 * @author Alexander Kotov (kotov.alex.22@gmail.com)
 */
public class BankServer {
    private final static int PORT = 12345;
    private final static int BACKLOG = 5;
    private final BankRequestProcessor bankRequestProcessor;

    public BankServer(final Bank bank) {
        bankRequestProcessor = new BankRequestProcessor(bank);
    }

    /**
     * This method starts Bank Server
     */
    public void start() {
        while (true) {
            run();
        }
    }

    private void sendMessage(final PrintWriter out, final String message) {
        out.println(message);
        System.out.println("server ==> " + "'" + message + "'");
    }

    private void processRequests(final BufferedReader in, final PrintWriter out) throws IOException {
        String request = null;
        do {
            request = in.readLine();
            System.out.println("'" + request + "' <== client");
            if ("close".equals(request)) {
                sendMessage(out, "close");
            } else {
                Command command = bankRequestProcessor.process(request);
                sendMessage(out, command.execute());
            }
        } while (!"close".equals(request));
    }

    private void run() {
        System.out.println("Waiting for client connection ...");
        try (ServerSocket socketFactory = new ServerSocket(PORT, BACKLOG);
             Socket socket = socketFactory.accept();
             PrintWriter output = new PrintWriter(socket.getOutputStream(), true);
             BufferedReader input = new BufferedReader(new InputStreamReader(socket.getInputStream()))) {

            System.out.println("Connection with " + socket.getInetAddress().getHostName() + " established");
            sendMessage(output, "Connection established");
            processRequests(input, output);

        } catch (IOException ioException) {
            ioException.printStackTrace();
            System.err.println(ioException.getMessage());
        } catch (NullPointerException nullPointerException) {
            nullPointerException.printStackTrace();
            System.err.println(nullPointerException.getMessage());
        }
    }
}
